﻿#include "AngleGraphicsItem.h"
#include "GraphicsDef.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QFocusEvent>

namespace OfUI {

	AngleGraphicsItem::AngleGraphicsItem(QGraphicsItem *parent)
		: BaseGraphicsItem(parent)
		, m_bAdding(true)
		, m_eSelType(SELECT_NONE)
	{
		setType(ItemType::ANGLE);
	}

	AngleGraphicsItem::~AngleGraphicsItem()
	{
	}

	void AngleGraphicsItem::setAnglePoint(const QPointF& firstPoint, const QPointF& secondPoint, const QPointF& thirdPoint)
	{
		prepareGeometryChange();
		m_firstPoint = firstPoint;
		m_secondPoint = secondPoint;
		m_thirdPoint = thirdPoint;
		emit signalDataChanged();
	}

	QPointF AngleGraphicsItem::getFirstPoint() const
	{
		return m_firstPoint;
	}

	QPointF AngleGraphicsItem::getSecondPoint() const
	{
		return m_secondPoint;
	}

	QPointF AngleGraphicsItem::getThirdPoint() const
	{
		return m_thirdPoint;
	}

	bool AngleGraphicsItem::isAdding() const
	{
		return m_bAdding;
	}

	bool AngleGraphicsItem::isEditing() const
	{
		return SELECT_NONE != m_eSelType;
	}

	bool AngleGraphicsItem::isVaild() const
	{
		QLineF firstLine(m_firstPoint, m_secondPoint);
		QLineF secondLine(m_thirdPoint, m_secondPoint);

		if (firstLine.length() > 1e-6 && secondLine.length() > 1e-6)
		{
			// [0, 360)
			double dAngle = firstLine.angleTo(secondLine);
			dAngle = qMin(dAngle, 360 - dAngle);

			// 认为角度 0、180 无意义，应该删除
			if (qAbs(dAngle - 180) > 1e-6 && dAngle > 1e-6)
			{
				return true;
			}
		}
		return false;
	}

	BaseGraphicsItem::MouseDragType AngleGraphicsItem::select(const QPointF & point, int * selType) const
	{
		MouseDragType eDragType = DRAG_NONE;
		SelectType eSelectType = SELECT_NONE;
		double dDistance = 5 / getViewScale();

		if (QLineF(m_firstPoint, point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_FIRST_POINT;
		}
		else if (QLineF(m_secondPoint, point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_SECOND_POINT;
		}
		else if (QLineF(m_thirdPoint, point).length() <= dDistance)
		{
			eDragType = DRAG_EDIT;
			eSelectType = SELECT_THIRD_POINT;
		}
		else
		{
			QLineF firstLine(m_firstPoint, m_secondPoint);
			QLineF secondLine(m_thirdPoint, m_secondPoint);

			if ((!firstLine.isNull() && distanceFromPointToLine(point, firstLine) < dDistance) ||
				(!secondLine.isNull() && distanceFromPointToLine(point, secondLine) < dDistance))
			{
				eDragType = DRAG_MOVE;
				eSelectType = SELECT_ALL;
			}
		}

		if (selType)
		{
			*selType = eSelectType;
		}
		return eDragType;
	}

	void AngleGraphicsItem::cursor(const QPointF & point, QCursor & cursor) const
	{
		int nType;
		if (BaseGraphicsItem::DRAG_NONE != select(point, &nType))
		{
			switch (nType)
			{
			case SELECT_FIRST_POINT:
			case SELECT_SECOND_POINT:
			case SELECT_THIRD_POINT:
				cursor = Qt::PointingHandCursor;
				break;
			case SELECT_ALL:
				cursor = Qt::SizeAllCursor;
				break;
			default:
				break;
			}
		}
	}

	void AngleGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
	{
		if (Qt::LeftButton == event->button())
		{
			m_pressMousePos = event->scenePos();

			if (isAdding())
			{
				if (SELECT_NONE == m_eSelType)
				{
					setAnglePoint(m_pressMousePos, m_pressMousePos, m_pressMousePos);
					m_eSelType = SELECT_SECOND_POINT;
					return;
				}
			}
			else
			{
				int nType = SELECT_NONE;
				if (BaseGraphicsItem::DRAG_NONE != select(m_pressMousePos, &nType))
				{
					m_eSelType = static_cast<SelectType>(nType);
					return;
				}
			}
		}
		QFocusEvent focusEvent(QEvent::FocusOut, Qt::OtherFocusReason);
		focusOutEvent(&focusEvent);
	}

	void AngleGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
	{
		if (Qt::LeftButton == event->button())
		{
			if (isAdding() && SELECT_SECOND_POINT == m_eSelType)
			{
				if (QLineF(m_firstPoint, m_secondPoint).length() > 1e-6)
				{
					m_eSelType = SELECT_THIRD_POINT;
					return;
				}
			}
		}
		QFocusEvent focusEvent(QEvent::FocusOut, Qt::OtherFocusReason);
		focusOutEvent(&focusEvent);
	}

	void AngleGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
	{
		if (SELECT_NONE == m_eSelType)
			return;

		QPointF mousePos = event->scenePos();
		QRectF sceneRect = scene()->sceneRect();
		// 保证鼠标在场景内
		mousePos.setX(qMin(mousePos.rx(), sceneRect.right()));
		mousePos.setY(qMin(mousePos.ry(), sceneRect.bottom()));
		mousePos.setX(qMax(mousePos.rx(), sceneRect.left()));
		mousePos.setY(qMax(mousePos.ry(), sceneRect.top()));

		QPointF firstPoint = m_firstPoint;
		QPointF secondPoint = m_secondPoint;
		QPointF thirdPoint = m_thirdPoint;

		if (SELECT_FIRST_POINT == m_eSelType)
		{
			firstPoint = mousePos;
			if (Qt::ShiftModifier & event->modifiers())
			{
				QLineF line = getStraightLineFromObliqueLine(QLineF(secondPoint, firstPoint));
				firstPoint = line.p2();
			}
		}
		else if (SELECT_SECOND_POINT == m_eSelType)
		{
			secondPoint = mousePos;
		}
		else if (SELECT_THIRD_POINT == m_eSelType)
		{
			thirdPoint = mousePos;
			if (Qt::ShiftModifier & event->modifiers())
			{
				QLineF line = getStraightLineFromObliqueLine(QLineF(secondPoint, thirdPoint));
				thirdPoint = line.p2();
			}
		}
		else if (SELECT_ALL == m_eSelType)
		{
			QPointF offsetPoint = mousePos - m_pressMousePos;
			firstPoint += offsetPoint;
			secondPoint += offsetPoint;
			thirdPoint += offsetPoint;
			m_pressMousePos = mousePos;
		}
		setAnglePoint(firstPoint, secondPoint, thirdPoint);
	}

	void AngleGraphicsItem::focusOutEvent(QFocusEvent * event)
	{
		Q_UNUSED(event);
		if (isAdding())
		{
			emit signalAddFinished();
			m_bAdding = false;
		}
		m_eSelType = SELECT_NONE;
	}

	QRectF AngleGraphicsItem::boundingRect() const
	{
		QPainterPath path;
		path.moveTo(m_firstPoint);
		path.lineTo(m_secondPoint);
		path.moveTo(m_secondPoint);
		path.lineTo(m_thirdPoint);

		double dRadius = 2 / getViewScale();
		path.addEllipse(m_firstPoint, dRadius, dRadius);
		path.addEllipse(m_secondPoint, dRadius, dRadius);
		path.addEllipse(m_thirdPoint, dRadius, dRadius);

		QRectF rectF = path.controlPointRect().adjusted(-5, -5, 5, 5);
		return rectF;
	}

	void AngleGraphicsItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget)
	{
		Q_UNUSED(option);
		Q_UNUSED(widget);

		if (this->scene())
		{
			painter->save();
			painter->setRenderHint(QPainter::Antialiasing);

			// 通过反向缩放painter实现矢量绘制效果
			double dViewScale = getViewScale();
			painter->scale(1 / dViewScale, 1 / dViewScale);

			// painter缩小，则绘制坐标放大，保证显示位置不变
			QPointF firstPoint = m_firstPoint * dViewScale;
			QPointF secondPoint = m_secondPoint * dViewScale;
			QPointF thirdPoint = m_thirdPoint * dViewScale;

			// 绘制线段
			painter->setPen(getPen(getState()));
			painter->drawLine(firstPoint, secondPoint);
			painter->drawLine(secondPoint, thirdPoint);

			// 叠加绘制选中状态 
			if (STATE_SELECT == getState())
			{
				double dRadius = 2;
				painter->drawEllipse(firstPoint, dRadius, dRadius);
				painter->drawEllipse(secondPoint, dRadius, dRadius);
				painter->drawEllipse(thirdPoint, dRadius, dRadius);
			}
			painter->restore();
		}
	}

}
